<?php


namespace rabbit;

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Exchange\AMQPExchangeType;
use PhpAmqpLib\Message\AMQPMessage;
use rabbit\exception\ConnectException;
use rabbit\exception\RabbitException;

/**
 * Class Rabbit
 * @package rabbit
 * @property Config config
 */
class Rabbit
{
    protected $container = [];

    protected $path;

    protected $rootPath;

    protected $configPath;

    protected $map = [
        'config'    => Config::class,
    ];
    /**
     * @var AMQPStreamConnection|null
     */
    private $connect;
    /**
     * @var mixed|\PhpAmqpLib\Channel\AMQPChannel|null
     */
    private $channel;

    public function __construct( string $rootPath = '' )
    {
        $this->path   = dirname(__DIR__) . DIRECTORY_SEPARATOR;
        $this->rootPath    = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath();
        $this->configPath     = $this->rootPath . 'config' . DIRECTORY_SEPARATOR;
        $this->loadConfig();
    }

    protected function getDefaultRootPath(){
        return dirname($this->path, 4) . DIRECTORY_SEPARATOR;
    }

    /**
     * 加载配置
     */
    protected function loadConfig(){
        $file = $this->configPath.'config.php';
        $this->config->load( $file, pathinfo( $file, PATHINFO_FILENAME) );
    }

    /**
     * @param string $exchange
     * @param string $routerKey
     * @param string $body
     * @param string $properties
     * @throws ConnectException
     */
    public function push( $exchange, $routerKey,  $body= '',$properties = ''){
        $message = new AMQPMessage($body,$properties);
        $this->getChannel()->basic_publish( $message, $exchange, $routerKey );
    }

    /**消费
     * @param $exchange
     * @param $routerKey
     * @param $queueName
     * @param Consumer $consumer
     *  @param string $consumerTag
     * @throws RabbitException
     */
    public function cost( $exchange, $routerKey, $queueName, $consumer, $consumerTag ){
        $this->getChannel();
        $this->channel->queue_declare($queueName);
        $this->channel->exchange_declare($exchange,AMQPExchangeType::DIRECT );
        $this->channel->queue_bind($queueName,$exchange,$routerKey);
        $this->channel->basic_consume($queueName, $consumerTag, false, false,false, false, [ $consumer,'messageHandler']);
        while ( $this->channel->is_consuming() ) {
            try {
                $this->channel->wait();
            }catch (\ErrorException $exception){
                throw new RabbitException( $exception->getMessage());
            }
        }
    }

    /**链接
     * @return AMQPStreamConnection|null
     */
    protected function getConnect(){
        if( is_null( $this->connect ) ){
            $this->connect = new AMQPStreamConnection($this->config->get('host'),$this->config->get('port'),$this->config->get('user'),$this->config->get('password'), $this->config->get('vhost','/'));
        }
        return $this->connect;
    }

    /**取一个通道
     * @return mixed|\PhpAmqpLib\Channel\AMQPChannel|null
     * @throws ConnectException
     */
    protected function getChannel(){
        if( is_null($this->connect) ){
            $this->getConnect();
        }
        if( !$this->connect->isConnected() ){
            throw new ConnectException('connect close');
        }

        if( is_null(  $this->channel ) || !$this->channel->is_open()){
            $this->channel = $this->connect->channel();
        }

        return $this->channel;
    }

    /**
     * @param $name
     * @return mixed|null
     */
    public function __get($name)
    {
        if( array_key_exists( $name, $this->container) ){
            return $this->container[$name];
        }
        if(array_key_exists( $name, $this->map) ){
            $this->container[ $name ] = new ($this->map[$name]);
            return   $this->container[ $name ];
        }
        return null;
    }

}